package node

import (
	//	"nextFlow/engine"
	"errors"
	"fmt"
	"github.com/tidwall/gjson"
	"nextFlow/types"
	"nextFlow/utils"
	"sync"
)

type NodeStruct struct {
	Config  types.H
	FlowCtx types.Flow
	Once    sync.Once
	rw      sync.RWMutex
}

func (this *NodeStruct) SetFlowCtx(ctx types.Flow) {
	this.FlowCtx = ctx
}

func (this *NodeStruct) Index() string {
	return this.ConfigGet("index").String()
}

func (this *NodeStruct) Id() string {
	return this.ConfigGet("Id").String()
}

func (this *NodeStruct) Type() string {
	return this.ConfigGet("type").String()
}

func (this *NodeStruct) ConfigGet(path string, def ...interface{}) gjson.Result {
	this.rw.RLock()
	defer this.rw.RUnlock()
	return this.Config.Get(path, def)
}

func (this *NodeStruct) ConfigSet(path string, value interface{}) error {
	this.rw.Lock()
	defer this.rw.Unlock()
	return this.Config.Set(path, value)
}

func New(config types.H) types.Node {
	return &NodeStruct{
		Config: config, // make(types.H),
	}
}

func (this *NodeStruct) Init() error {

	this.Once.Do(func() {
		fmt.Println("执行task => ", this.Index(), this.Type())
	})

	return nil
}

func (this *NodeStruct) OnHandle() error {

	// 初始化一次
	this.Init()

	var relationType = ""

	switch this.Type() {
	case "if", "case", "while":
		relationType = this.FlowCtx.ExprCalc(this.ConfigGet(fmt.Sprintf("inputs.%s.cond", this.Type())).String())
		if relationType == types.True {
			if this.Type() == "while" {
				this.ConfigSet("inputs.while.current", this.ConfigGet("inputs.while.current").Int()+1)
			}
		}
	case "delay":
		return nil
	case "stop":
		return nil
	case "func":
		out, _, _ := this.FlowCtx.JsDo(types.H{"@this": this.ConfigGet("inputs").Value()})
		this.ConfigSet("outputs", out)
	case "trigger":

		outFunc, outTrigger, err := this.FlowCtx.JsDo(types.H{"@this": this.ConfigGet("inputs").Value()})
		if err != nil {
			this.FlowCtx.Trace(err)
			return err
		}
		this.ConfigSet("outputs", outFunc)

		if this.ConfigGet("outputs").String() == "" {
			return errors.New("触发失败")
		} else {
			this.FlowCtx.Trigger(outTrigger)
		}

		return nil
	}

	this.HandleNext(relationType)

	return nil
}

func (this *NodeStruct) HandleNext(relationType string) {

	if nodes, ok := this.FlowCtx.GetNextNodes(this.Index(), relationType); ok {

		for _, c := range nodes {

			if utils.CompareInt(c.Index(), this.Index()) {

				if c.Type() == "while" {
					c.ConfigSet("inputs.while.current", 0)
				}

				c.ConfigSet("outputs", types.H{})

			}

			c.OnHandle()
		}
	}

}

func (this *NodeStruct) Destroy() {
}
